#include "mysql_user_storage.hpp"
#include "../common/logger.hpp"
#include "../core/di_container.hpp"
#include <optional>
#include <nlohmann/json.hpp>
#include <chrono>
#include <exception>

namespace storage {

MysqlUserStorage::MysqlUserStorage() {
    mysql_ = DIContainer::get<MysqlManager>();
    redis_ = DIContainer::get<RedisManager>();
}

bool MysqlUserStorage::create_user(const UserEntity& user) {
    try {
        // 检查用户名是否已存在
        if (exists_by_username(user.username)) {
            return false;
        }
        
        // 使用预处理语句插入用户
        // user.created_at, user.updated_at 是时间戳，需要转换为字符串
        auto result = mysql_->execute(
            "INSERT INTO users (username, password_hash) "
            "VALUES (?, ?)",
            {user.username, user.password_hash}
        );
        
        if (result > 0) {
            // 更新缓存
            // cache_user(user);
            // invalidate_username_exists_cache(user.username);
            return true;
        }
        return false;
    } catch (const std::exception& e) {
        // // 如果用户名已存在，则返回false
        // if (is_mysql_duplicate_entry_error(e)) {
        //     Logger::warn("Failed to create user: {}", user.username);
        //     return false;
        // }
        Logger::error("Failed to create user: {}", e.what());
        return false;
    }
}

// bool MysqlUserStorage::is_mysql_duplicate_entry_error(const std::exception& e) {
//     return e.code() == 1062;
// }

std::optional<UserEntity> MysqlUserStorage::get_user_by_username(const std::string& username) {
    try {
        // 先查询缓存
        std::string cache_key = "user:" + username;
        std::optional<std::string> cached_value = redis_->get(cache_key);
        if (cached_value) {
            return deserialize_user(*cached_value);
        }

        // 缓存未命中，查询数据库
        auto rows = mysql_->query(
            "SELECT id, username, password_hash"
            "FROM users WHERE username = ?",
            {username}
        );
        if (rows.empty()) {
            return std::nullopt;
        }

        UserEntity user;
        user.id = rows[0].get<int64_t>("id");
        user.username = rows[0].get<std::string>("username");
        user.password_hash = rows[0].get<std::string>("password_hash");

        // 如果数据库中没有is_online字段，则设置为false
        user.is_online = false;
            
        // 更新缓存
        cache_user(user);
        return user;
    } catch (const std::exception& e) {
        Logger::error("Failed to get user: {}", e.what());
        return std::nullopt;
    }
}

std::optional<UserEntity> MysqlUserStorage::get_user_by_id(int64_t user_id) {
    try {
        auto rows = mysql_->query(
            "SELECT id, username, password_hash, is_online, created_at, updated_at "
            "FROM users WHERE id = ?",
            {user_id}
        );
        if (rows.empty()) { 
            return std::nullopt;
        }

        UserEntity user;
        user.id = rows[0].get<int64_t>("id");
        user.username = rows[0].get<std::string>("username");
        user.password_hash = rows[0].get<std::string>("password_hash");
        user.is_online = rows[0].get<bool>("is_online");
            
        // 更新缓存
        cache_user(user);
        return user;

    } catch (const std::exception& e) {
        Logger::error("Failed to get user by id: {}", e.what());
        return std::nullopt;
    }
}

bool MysqlUserStorage::update_user(const UserEntity& user) {
    try {
        auto result = mysql_->execute(
            "UPDATE users SET username = ?, password_hash = ?, is_online = ?, updated_at = NOW() "
            "WHERE id = ?",
            {user.username, user.password_hash, user.is_online ? 1 : 0, user.id}
        );
        
        if (result > 0) {
            // 更新缓存
            invalidate_user_cache(user.username);
            cache_user(user);
            return true;
        }
        return false;
    } catch (const std::exception& e) {
        Logger::error("Failed to update user: {}", e.what());
        return false;
    }
}   

bool MysqlUserStorage::delete_user(int64_t user_id) {
    try {
        // 先获取用户信息，以便于后续清除缓存
        auto user = get_user_by_id(user_id);
        if (!user) {
            return false;
        }
        
        auto result = mysql_->execute(
            "DELETE FROM users WHERE id = ?",
            {user_id}
        );
        
        if (result > 0) {
            // 清除缓存
            invalidate_user_cache(user->username);
            invalidate_username_exists_cache(user->username);
            return true;
        }
        return false;
    } catch (const std::exception& e) {
        Logger::error("Failed to delete user: {}", e.what());
        return false;
    }
}

// 检查用户名是否存在
// 如果存在，则返回true，否则返回false
// 暂时不考虑性能问题，直接访问数据库
// username_exists 是 username_exists:username 的缩写
bool MysqlUserStorage::exists_by_username(const std::string& username) {
    try {
        // 检查缓存
        std::string cache_key = username_exists_key(username);
        auto cached_value = redis_->get(cache_key);
        if (cached_value) {
            return true;
        }

        auto rows = mysql_->query(
            "SELECT COUNT(*) as count FROM users WHERE username = ?",
            {username}
        );
        
        if (!rows.empty()) {
            return rows[0].get<int>("count") > 0;
        }
        return false;
    } catch (const std::exception& e) {
        Logger::error("Failed to check if user exists: {}", e.what());
        return false;
    }
}

void MysqlUserStorage::cache_user(const UserEntity& user) {
    try {
        std::string cache_key = user_key(user.username);
        std::string user_data = serialize_user(user);
        redis_->setex(cache_key, 3600, user_data); // 1小时过期

    } catch (const std::exception& e) {
        Logger::error("Failed to cache user: {}", e.what());
    }
}

void MysqlUserStorage::cache_username_exists(const std::string& username) {
    try {
        std::string cache_key = username_exists_key(username);
        redis_->setex(cache_key, 3600, "1");
    } catch (const std::exception& e) {
        Logger::error("Failed to cache username exists: {}", e.what());
    }
}

std::string MysqlUserStorage::user_key(const std::string& username) const {
    return "user:" + username;
}

std::string MysqlUserStorage::username_exists_key(const std::string& username) const {
    return "username_exists:" + username;
}

void MysqlUserStorage::invalidate_username_exists_cache(const std::string& username) {
    try {
        std::string cache_key = username_exists_key(username);
        redis_->del(cache_key);
    } catch (const std::exception& e) {
        Logger::error("Failed to invalidate username exists cache: {}", e.what());
    }
}
std::string MysqlUserStorage::serialize_user(const UserEntity& user) {
    // 这里需要实现对用户对象的序列化，例如转为JSON
    nlohmann::json j;
    j["id"] = user.id;
    j["username"] = user.username;
    j["password_hash"] = user.password_hash;
    j["is_online"] = user.is_online;
    return j.dump();
}

UserEntity MysqlUserStorage::deserialize_user(const std::string& data) {
    auto j = nlohmann::json::parse(data);
    UserEntity user;
    user.id = j["id"];
    user.username = j["username"];
    user.password_hash = j["password_hash"];
    user.is_online = j["is_online"];
    return user;
}

bool MysqlUserStorage::store_session(const UserSession& session) {
    try {
        std::string session_key = "session:" + session.username;
        
        // 序列化会话信息
        std::string session_data = serialize_session(session);
        
        // 计算过期时间
        // auto ttl = std::chrono::duration_cast<std::chrono::seconds>(
        //     session.expires_at - std::chrono::system_clock::now()
        // ).count();
        
        // 存储会话并设置过期时间
        redis_->setex(session_key, 3600, session_data);
        return true;
    } catch (const std::exception& e) {
        Logger::error("Failed to store session: {}", e.what());
        return false;
    }
}

bool MysqlUserStorage::delete_session(const std::string& username) {
    try {
        std::string session_key = "session:" + username;
        redis_->del(session_key);
        return true;
    } catch (const std::exception& e) {
        Logger::error("Failed to delete session: {}", e.what());
        return false;
    }   
}

std::string MysqlUserStorage::serialize_session(const UserSession& session) {
    nlohmann::json j;
    j["username"] = session.username;
    j["session_token"] = session.session_token;
    // j["expires_at"] = session.expires_at;
    return j.dump();
}

UserSession MysqlUserStorage::deserialize_session(const std::string& data) {
    auto j = nlohmann::json::parse(data);
    UserSession session;
    session.username = j["username"];
    session.session_token = j["session_token"];
    // 反序列化过期时间
    // session.expires_at = j["expires_at"];
    return session;
}

std::optional<UserSession> MysqlUserStorage::get_session(const std::string& username) {
    try {
        std::string session_key = "session:" + username;
        auto session_data = redis_->get(session_key);
        if (session_data) {
            return deserialize_session(*session_data);
        }
        return std::nullopt;
    } catch (const std::exception& e) {
        Logger::error("Failed to get session: {}", e.what());
        return std::nullopt;
    }   
}

void MysqlUserStorage::invalidate_user_cache(const std::string& username) {
    try {
        std::string cache_key = "user:" + username;
        redis_->del(cache_key);
    } catch (const std::exception& e) {
        Logger::error("Failed to invalidate user cache: {}", e.what());
    }
}

} // namespace storage
